Region Allocation
You can create a new object on the heap using one of a few kinds of expression:
newexpr evaluates expr, places the result into the heap, and returns a pointer to the result. It is roughly equivalent tot @ temp = malloc(sizeof(t)); // where t is the type of expr *temp = _ expr_;For example,
new 17allocates space for an integer on the heap, initializes it to 17, and returns a pointer to the space. For another example, if we have declaredstruct Pair { int x; int y; };then
new Pair(7,9)allocates space for two integers on the heap, initializes the first to 7 and the second to 9, and returns a pointer to the first.newarray-initializer allocates space for an array, initializes it according to array-initializer, and returns a pointer to the first element. For example,let x = new { 3, 4, 5 };declares a new array containing 3, 4, and 5, and initializes
xto point to the first element. More interestingly,new { for _ identifier_ < _ expr_1 : _ expr_2 }is roughly equivalent to
unsigned int sz = _ expr_1; t @ temp = malloc(sz * sizeof(t2)); // where t is the type of expr for (int _ identifier_ = 0; _ identifier_ < sz; _ identifier_++) temp[_ identifier_] = _ expr_2;That is, expr1 is evaluated first to get the size of the new array, the array is allocated, and each element of the array is initialized by the result of evaluating expr2. expr2 may use identifier, which holds the index of the element currently being initialized.
For example, this function returns an array containing the first n positive even numbers:
int *@fat n_evens(int n) { return new {for next < n : 2*(next+1)}; }Note that:
- expr1 is evaluated exactly once, while expr2 is evaluated expr1 times.
- expr1 might evaluate to 0.
- expr1 might evaluate to a negative number. If so, it is implicitly converted to a very large unsigned integer; the allocation is likely to fail due to insufficient memory. Currently, this will cause a crash!!
- Currently, for array initializers are the only way to create an object whose size depends on run-time data.
malloc(sizeof(type)). Returns a@notnullpointer to an uninitialized value of type type.malloc(n*sizeof(type))ormalloc(sizeof(type)*n). The type must be a bits-only type (i.e., cannot contain pointers, tagged unions, zero-terminated values, etc.) Ifnis a compile-time constant expression, returns a@thinpointer with@numelts(n). Ifnis not a compile-time constant, returns a@fatpointer to the sequence ofnuninitialized values.calloc(n,sizeof(type)). Similar to themalloccase above, but returns memory that is zero’d. Therefore,callocsupports types that are bits-only or zero-terminated.malloc(e)whereeis an expression not of one of the above forms. Ifeis constant, returns achar *@numelts(e)@nozerotermotherwise returns a char*@fat@nozeroterm.
Objects within regions can be created using the following analogous expressions.
rnew(identifier)exprrnew(identifier)array-initializerrmalloc(identifier,sizeof(type))rmalloc(identifier,n*sizeof(type))rmalloc(identifier,sizeof(type)*n)rmalloc(identifier,e))rcalloc(identifier,n,sizeof(type))
Note that new, malloc, calloc, rnew, rmalloc and rcalloc are keywords.
Here, the first argument specifies a region handle. The Cyclone library has a global variable Core::heap_region which is a handle for the heap region. So, for example, rnew (heap_region) expr allocates memory in the heap region which is initialized with expr. Moreover, new expr can be replaced with rnew(heap_region) expr.
The only way to create an object in a stack region is declaring it as
a local variable. Cyclone does not currently support salloc; use a
lexical region instead.